home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 15 / develop 15 code / Floating Windows / Source / WindowExtensions.c next >
Encoding:
C/C++ Source or Header  |  1994-03-16  |  28.4 KB  |  1,002 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        WindowExtensions.c
  3.     
  4.     Contains:    Routines to support floating windows
  5.     
  6.     Written by:    Dean Yu
  7.     
  8.     Copyright:    © 1993 Apple Computer, Inc.
  9.     
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Events.h>
  14. #include <GestaltEqu.h>
  15. #include <Memory.h>
  16. #include <Menus.h>
  17. #include <Processes.h>
  18. #include <Resources.h>
  19. #include <SysEqu.h>
  20. #include <ToolUtils.h>
  21. #include <Windows.h>
  22.  
  23. #include "WindowExtensions.h"
  24.  
  25. // Internal routine prototypes
  26.  
  27. static void ActivateWindow(WindowRef theWindow);
  28. static void DeactivateWindow(WindowRef theWindow);
  29. static void HighlightAndActivateWindow(WindowRef theWindow, Boolean activate);
  30. static WindowRef GetWindowList(void);
  31. static void SetWindowList(WindowRef windowReference);
  32.  
  33. //
  34. // NewWindowReference
  35. //
  36. //    Create a new window, and return a reference to it.
  37. //
  38.  
  39. pascal OSErr NewWindowReference(WindowRef *windowReference, const Rect *boundsRect,
  40.  ConstStr255Param title, Boolean visible, WindowAttributes attributes, WindowRef behind,
  41.  long refCon, ActivateHandlerUPP activateHandlerProc)
  42. {
  43.     WindowAttributes    titleBarType;
  44.     WindowRef            newWindowReference;
  45.     WindowRef            lastFloater;
  46.     long                gestaltResult;
  47.     OSErr                result = noErr;
  48.     OSErr                gestaltError;
  49.     short                procID;
  50.     Boolean                hasGoAway = false;
  51.     
  52.     // Determine the type of title bar this window has, if any.
  53.     
  54.     titleBarType = attributes & kWindowTitlebarMask;
  55.     if (titleBarType != 0) {
  56.         switch (titleBarType) {
  57.             case kHasRoundedTitlebarMask:
  58.             case kHasDocumentTitlebarMask:    if ((behind == (WindowRef) -1) &&
  59.                                                 ((lastFloater = LastFloatingWindow()) != nil))
  60.                                                 behind = lastFloater;
  61.                                             
  62.                                             if (titleBarType == kHasRoundedTitlebarMask)
  63.                                                 procID = kRoundedWindowProc;
  64.                                             else
  65.                                                 procID = kStandardDocumentWindowProc;
  66.                                             break;
  67.             case kHasPaletteTitlebarMask:    if (((behind == nil) && (FrontNonFloatingWindow() != nil)) ||
  68.                                                 ((behind != (WindowRef) -1) && (GetWindowKind(behind) != kApplicationFloaterKind))) {
  69.                                                 *windowReference = 0;
  70.                                                 return kInvalidWindowOrderingError;
  71.                                             }
  72.                                             procID = kFloatingWindowProc;
  73.                                             break;
  74.             default:                        procID = kStandardDocumentWindowProc;
  75.                                             result = kUndefinedTitleBarTypeError;
  76.                                             break;
  77.         }
  78.         
  79.         // This window has a title bar.  See what kind of gadgets it has in it.
  80.     
  81.         if (attributes & kHasModalBorderMask)        // Moveable modals don’t get zoom, close, or grow boxes
  82.             procID += movableDBoxProc;
  83.         else {
  84.             if (attributes & kHasCloseBoxMask)
  85.                 hasGoAway = true;
  86.             if (attributes & kHasZoomBoxMask)
  87.                 procID += zoomDocProc;
  88.             if (!(attributes & kHasGrowBoxMask))
  89.                 procID += noGrowDocProc;
  90.         }
  91.     }
  92.     
  93.     // This window has no title bar, so it’s a dialog of some sort.
  94.     // We’re going to be dictatorial and say that these types of windows
  95.     // can only come up in front.
  96.     
  97.     else {
  98.         if (behind != (WindowRef) -1) {
  99.             *windowReference = 0;
  100.             return kInvalidWindowOrderingError;
  101.         }
  102.         
  103.         procID = dBoxProc;                                // Start with the standard dialog type
  104.         if (!(attributes & kHasModalBorderMask)) {
  105.             procID = plainDBox;                            // This isn’t the standard modal type
  106.             if (attributes & kHasThickDropShadowMask)    // These types can have a deeper drop shadow
  107.                 procID = altDBoxProc;
  108.         }
  109.     }
  110.     
  111.     newWindowReference = (WindowRef) NewPtr(sizeof(WindowRecordExtensions));
  112.     
  113.     if (MemError() == noErr) {
  114.  
  115.     // Call the real Window Manager routine to create the window:
  116.     // If Color Quickdraw is available, always create a color window.  If Color Quickdraw
  117.     // is not around, or Gestalt spewed, create a classic window.
  118.     
  119.         gestaltError = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  120.         if ((gestaltError != noErr) || (gestaltResult == gestaltOriginalQD))
  121.             NewWindow(newWindowReference, boundsRect, title, false, procID, (WindowPtr) behind,
  122.                 hasGoAway, refCon);
  123.         else
  124.             NewCWindow(newWindowReference, boundsRect, title, false, procID, (WindowPtr) behind,
  125.                 hasGoAway, refCon);
  126.         
  127.     // If a window was successfully created, set its activate event handler proc and show
  128.     // it if the caller wanted a visible window.
  129.     
  130.         *windowReference = newWindowReference;        // Return a reference to the window
  131.         SetActivateHandlerProc(newWindowReference, activateHandlerProc);
  132.         
  133.         if (attributes & kHasPaletteTitlebarMask)    // Set the windowKind for floating windows
  134.             SetWindowKind(newWindowReference, kApplicationFloaterKind);
  135.             
  136.         if (visible)                                // Show the window
  137.             ShowReferencedWindow(newWindowReference);
  138.     }
  139.     else {
  140.         *windowReference = 0;
  141.         result = kWindowNotCreatedError;
  142.     }
  143.         
  144.     return result;
  145. }
  146.  
  147. //
  148. // GetNewWindowReference
  149. //
  150. //    Create a window based on information in the specified resource.
  151. //
  152.  
  153. pascal OSErr GetNewWindowReference(WindowRef *windowReference, short windResourceID,
  154.  WindowRef behind, ActivateHandlerUPP activateHandler)
  155. {
  156.     WindowRef    newWindowReference;
  157.     WindowRef    lastFloatingWindow;
  158.     WindowRef    windowReferenceStorage;
  159.     long        gestaltResult;
  160.     OSErr        gestaltError;
  161.     OSErr        result;
  162.     short        defProcID;
  163.     
  164.     result = noErr;
  165.     windowReferenceStorage = (WindowRef) NewPtr(sizeof(WindowRecordExtensions));
  166.     
  167.     if (MemError() == noErr) {
  168.  
  169.     // Create a window based on the specified 'WIND' resource.  If Color Quickdraw
  170.     // is around, create a color window, otherwise, make a black and white one.
  171.     
  172.         gestaltError = Gestalt(gestaltQuickdrawVersion, &gestaltResult);
  173.         if ((gestaltError != noErr) || (gestaltResult == gestaltOriginalQD))
  174.             newWindowReference = (WindowRef) GetNewWindow(windResourceID, windowReferenceStorage, (WindowPtr) behind);
  175.         else
  176.             newWindowReference = (WindowRef) GetNewCWindow(windResourceID, windowReferenceStorage, (WindowPtr) behind);
  177.     
  178.     // If we got a window, create the reference, then make sure the windowKind field is
  179.     // set correctly for floating windows.
  180.     
  181.         if (newWindowReference != nil) {
  182.             *windowReference = newWindowReference;
  183.             SetActivateHandlerProc(newWindowReference, activateHandler);
  184.             
  185.     // Figure out if this is a floating window, based upon the resource ID of the 'WDEF'.
  186.     // This is a really wierd way of doing it, but this allows the 'WIND' resource to
  187.     // describe the floatability of a window.
  188.     //
  189.     // A little known fact about GetResInfo is that if you specify nil for any of the
  190.     // info parameters, then it won’t return that information.  Handy, huh?
  191.     
  192.             GetResInfo(GetWindowDefProc(newWindowReference), &defProcID, nil, nil);
  193.             
  194.             if (defProcID == rFloatingWindowProc) {
  195.             
  196.     // Return an error if it’s a floating window being created behind a non floating window.
  197.             
  198.                 if (((behind == nil) && (FrontNonFloatingWindow() != nil)) ||
  199.                     ((behind != (WindowRef) -1) && (GetWindowKind(behind) != kApplicationFloaterKind))) {
  200.                     *windowReference = 0;
  201.                     return kInvalidWindowOrderingError;
  202.                 }
  203.                 else {
  204.                     SetWindowKind(newWindowReference, kApplicationFloaterKind);
  205.                     HiliteWindow((WindowPtr) newWindowReference, true);
  206.                 }
  207.             }
  208.             else
  209.             
  210.     // If we’re not creating a floating window, but the application wanted it in the
  211.     // front, create the window behind the last floating window.
  212.             
  213.                 if (behind == (WindowRef) -1) {
  214.                     lastFloatingWindow = LastFloatingWindow();
  215.                     
  216.                     if (lastFloatingWindow != nil)
  217.                         SendBehind((WindowPtr) newWindowReference, (WindowPtr) lastFloatingWindow);
  218.                     else
  219.                         BringToFront((WindowPtr) newWindowReference);
  220.                 }
  221.         }
  222.         else {
  223.             DisposePtr((Ptr) windowReferenceStorage);
  224.             *windowReference = 0;
  225.             result = kWindowNotCreatedError;
  226.         }
  227.     }
  228.     else {
  229.         *windowReference = 0;
  230.         result = kWindowNotCreatedError;
  231.     }
  232.     
  233.     return result;
  234. }
  235.  
  236. //
  237. // DisposeWindowReference
  238. //
  239. //    Free the memory used by a window.  If it is visible, hide it first so
  240. //    that the proper activate and deactivate events are sent.
  241. //
  242.  
  243. pascal void DisposeWindowReference(WindowRef windowReference)
  244. {
  245.     if (GetWindowVisible(windowReference))
  246.         HideReferencedWindow(windowReference);
  247.     CloseWindow((WindowPtr) windowReference);
  248.     DisposePtr((Ptr) windowReference);
  249. }
  250.  
  251. //
  252. // SelectedReferencedWindow
  253. //
  254. // Select the specified window, and bring it to the front if its portion
  255. // of the window list.
  256. //
  257.  
  258. pascal void SelectReferencedWindow(WindowRef windowToSelect)
  259. {
  260.     WindowRef            currentFrontWindow;
  261.     WindowRef            lastFloatingWindow;
  262.     Boolean                isFloatingWindow;
  263.  
  264.     if (GetWindowKind(windowToSelect) == kApplicationFloaterKind) {
  265.         isFloatingWindow = true;
  266.         currentFrontWindow = (WindowRef) FrontWindow();
  267.     }
  268.     else {
  269.         isFloatingWindow = false;
  270.         currentFrontWindow = FrontNonFloatingWindow();
  271.         lastFloatingWindow = LastFloatingWindow();
  272.     }
  273.  
  274.     // Be fast (and lazy) and do nothing if we don’t have to.
  275.  
  276.     if (currentFrontWindow != windowToSelect) {
  277.  
  278.     // Selecting floating windows are easy, since they’re always active
  279.  
  280.         if (isFloatingWindow)
  281.             BringToFront((WindowPtr) windowToSelect);
  282.         else {
  283.     
  284.     // If there are no floating windows, we can call SelectWindow like the good ol’ days
  285.  
  286.             if (lastFloatingWindow == nil)
  287.                 SelectWindow((WindowPtr) windowToSelect);
  288.             else {
  289.  
  290.     // Deactivate the window currently in front.
  291.                 
  292.                 DeactivateWindow(currentFrontWindow);
  293.     
  294.     // Bring it behind the last floating window and activate it.
  295.     // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  296.     // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  297.     // this is no longer necessary.
  298.  
  299.                 SendBehind((WindowPtr) windowToSelect, (WindowPtr) lastFloatingWindow);
  300.                 ActivateWindow(windowToSelect);
  301.             }
  302.         }
  303.     }
  304. }
  305.  
  306. //
  307. // ShowReferencedWindow
  308. //
  309. //    Show the specified window.  If the window is the frontmost document window,
  310. //    unhighlight the window behind it, deactivate it, and activate this one.
  311. //
  312.  
  313. pascal void ShowReferencedWindow(WindowRef windowToShow)
  314. {
  315.     WindowRef            windowBehind;
  316.     WindowRef            frontNonFloatingWindow;
  317.     ActivateHandlerUPP    activateHandlerProc;
  318.     short                windowClass;
  319.     Boolean                windowIsInFront = false;
  320.     
  321.     if (GetWindowVisible(windowToShow) != false)
  322.         return;
  323.         
  324.     windowClass = GetWindowKind(windowToShow);
  325.     
  326.     // If the window behind the window to show is currently the frontmost document window,
  327.     // unhighlight it, and highlight the new front window.
  328.     
  329.     if (windowClass != kApplicationFloaterKind) {
  330.         windowBehind = GetNextWindow(windowToShow);
  331.         if (windowBehind == FrontNonFloatingWindow()) {
  332.             if (windowBehind != nil)
  333.                 DeactivateWindow(windowBehind);
  334.  
  335.     // Set the highlight state so the window appears highlighted from the start.
  336.     
  337.             SetWindowHilite(windowToShow, true);
  338.             windowIsInFront = true;
  339.         }
  340.     }
  341.     else {
  342.     
  343.     // A floating window is about to be shown. Make sure the windows in the window list
  344.     // are all in the right place.
  345.     
  346.         ValidateWindowList();
  347.         
  348.     // Check to see if a modal window is up before trying to highlight it.
  349.     
  350.         frontNonFloatingWindow = FrontNonFloatingWindow();
  351.         if ((frontNonFloatingWindow != nil) &&
  352.             (frontNonFloatingWindow == (WindowRef) FrontWindow()) &&
  353.             (WindowIsModal(frontNonFloatingWindow)))
  354.             SetWindowHilite(windowToShow, false);
  355.         else {
  356.             SetWindowHilite(windowToShow, true);
  357.             windowIsInFront = true;
  358.         }
  359.     }
  360.     
  361.     // Show the window
  362.     
  363.     ShowHide((WindowPtr) windowToShow, true);
  364.     
  365.     // If this is the new frontmost document window or a floating window, send it an activate event
  366.     
  367.     if (windowIsInFront) {
  368.         activateHandlerProc = GetActivateHandlerProc(windowToShow);
  369.         if (activateHandlerProc != nil)
  370.             CallActivateHandlerProc(activateHandlerProc, windowToShow, kActivateWindow);
  371.     }
  372. }
  373.  
  374. //
  375. // HideReferencedWindow
  376. //
  377. //    Hide the specified window.  If it is frontmost, move it behind the window immediately
  378. //    behind it, like HideWindow does.
  379. //
  380.  
  381. pascal void HideReferencedWindow(WindowRef windowToHide)
  382. {
  383.     WindowRef            frontFloater;
  384.     WindowRef            frontNonFloater;
  385.     WindowRef            lastFloater;
  386.     WindowRef            windowBehind;
  387.     
  388.     // Don’t do anything if the window is already invisible.
  389.     
  390.     if (GetWindowVisible(windowToHide) == false)
  391.         return;
  392.     
  393.     // Get the first visible floating window, if any.
  394.     
  395.     frontFloater = (WindowRef) FrontWindow();
  396.     if (GetWindowKind(frontFloater) != kApplicationFloaterKind)
  397.         frontFloater = nil;
  398.         
  399.     // Get the first visible document window, if any.
  400.     
  401.     frontNonFloater = FrontNonFloatingWindow();
  402.     
  403.     // Hide the window.
  404.     
  405.     ShowHide((WindowPtr) windowToHide, false);
  406.     
  407.     // If the frontmost floating window is being hidden, move it behind the floating window
  408.     // behind it, if there is one.
  409.     
  410.     if (windowToHide == frontFloater) {
  411.         windowBehind = GetNextWindow(windowToHide);
  412.         
  413.     // Only do the rearrangement if there’s another floating window.
  414.     
  415.         if ((windowBehind != nil) &&
  416.             (GetWindowKind(windowBehind) == kApplicationFloaterKind)) {
  417.             SetNextWindow(windowToHide, GetNextWindow(windowBehind));
  418.             SetNextWindow(windowBehind, windowToHide);
  419.             SetWindowList(windowBehind);
  420.         }
  421.     }
  422.     else {
  423.     
  424.     // If the frontmost document window is behind hidden, send it behind the window
  425.     // behind it.
  426.     
  427.         if (windowToHide == frontNonFloater) {
  428.             windowBehind = GetNextWindow(windowToHide);
  429.             
  430.             if (windowBehind != nil) {
  431.                 SetNextWindow(windowToHide, GetNextWindow(windowBehind));
  432.                 SetNextWindow(windowBehind, windowToHide);
  433.                 
  434.     // Set the next link of the last floating window to point to the previously second
  435.     // to front document window. If there was no floating window, change the beginning
  436.     // of the window list.
  437.     
  438.                 lastFloater = LastFloatingWindow();
  439.                 if (lastFloater != nil)
  440.                     SetNextWindow(lastFloater, windowBehind);
  441.                 else
  442.                     SetWindowList(windowBehind);
  443.                 
  444.     // The window behind it is now the front document window.  Highlight it and send it
  445.     // and activate event.
  446.                 
  447.                 ActivateWindow(windowBehind);
  448.             }
  449.         }
  450.     }
  451. }
  452.  
  453. pascal void DragReferencedWindow(WindowRef windowToDrag, Point startPoint, const Rect *draggingBounds)
  454. {
  455.     Rect        dragRect;
  456.     KeyMap        keyMap;
  457.     GrafPtr        savePort;
  458.     GrafPtr        windowManagerPort;
  459.     RgnHandle    dragRegion;
  460.     RgnHandle    windowContentRegion;
  461.     long        dragResult;
  462.     short        topLimit;
  463.     short        newHorizontalWindowPosition;
  464.     short        newVerticalWindowPosition;
  465.     short        horizontalOffset;
  466.     short        verticalOffset;
  467.     Boolean        commandKeyDown = false;
  468.     
  469.     if (WaitMouseUp()) {
  470.     
  471.     // Adjust the top of the dragging rectangle so that it’s below the menu bar
  472.     
  473.         topLimit = GetMBarHeight() + 4;
  474.         dragRect = *draggingBounds;
  475.         if (dragRect.top < topLimit)
  476.             dragRect.top = topLimit;
  477.     
  478.     // Set up the Window Manager port.
  479.     
  480.         GetPort(&savePort);
  481.         GetWMgrPort(&windowManagerPort);
  482.         SetPort(windowManagerPort);
  483.         SetClip(GetGrayRgn());
  484.         
  485.     // Check to see if the command key is down.  If it is, don’t bring the window to the
  486.     // front after the move.  Trying to do Pascal stuff in C is so much fun.  GetKeys()
  487.     // is a total pain to try to use properly from C, so I’m going to hard code where the
  488.     // command key is in the KeyMap array.
  489.     
  490.         GetKeys(keyMap);
  491.         if (keyMap[1] & 0x8000)
  492.             commandKeyDown = true;
  493.     
  494.         if ((commandKeyDown == true) ||
  495.             (GetWindowKind(windowToDrag) != kApplicationFloaterKind)) {
  496.             
  497.             if (commandKeyDown == false)
  498.     
  499.     // If there are floating windows, clip the dragging outline to draw behind the floaters.
  500.     
  501.                 ClipAbove((WindowPeek) FrontNonFloatingWindow());
  502.             else
  503.             
  504.     // If the command key was down, clip the outline to draw behind any windows above
  505.     // the window being dragged.
  506.     
  507.                 ClipAbove((WindowPeek) windowToDrag);
  508.         }
  509.             
  510.     // Create a region to drag
  511.     
  512.         dragRegion = NewRgn();
  513.         CopyRgn(GetStructureRegion(windowToDrag), dragRegion);
  514.         
  515.     // Drag the window around
  516.     
  517.         dragResult = DragGrayRgn(dragRegion, startPoint, &dragRect, &dragRect, noConstraint, nil);
  518.     
  519.     // Restore the port for coordinate conversion.
  520.     
  521.         SetPort(savePort);
  522.  
  523.         if (dragResult != 0) {
  524.             horizontalOffset = dragResult & 0xFFFF;
  525.             verticalOffset = dragResult >> 16;
  526.     
  527.     // Only move it if it stayed inside the dragging box.
  528.     
  529.             if (verticalOffset != -32768) {
  530.                 windowContentRegion = GetContentRegion(windowToDrag);
  531.                 newHorizontalWindowPosition = (**windowContentRegion).rgnBBox.left + horizontalOffset;
  532.                 newVerticalWindowPosition = (**windowContentRegion).rgnBBox.top + verticalOffset;
  533.                 
  534.                 MoveWindow((WindowPtr) windowToDrag, newHorizontalWindowPosition, newVerticalWindowPosition, false);
  535.                 
  536.             }
  537.         }
  538.     
  539.     // Bring the window forward if the command key wasn’t down
  540.     
  541.         if (commandKeyDown == false)
  542.             SelectReferencedWindow(windowToDrag);
  543.     
  544.     // Get rid of the dragging region
  545.     
  546.         DisposeRgn(dragRegion);
  547.     }
  548. }
  549.  
  550. //
  551. // FrontNonFloatingWindow
  552. //
  553. //    Return the first visible window that is not a floating window.
  554. //
  555.  
  556. pascal WindowRef FrontNonFloatingWindow(void)
  557. {
  558.     WindowRef    theWindow;
  559.     
  560.     // Get the first visible window in the window list.
  561.     
  562.     theWindow = (WindowRef) FrontWindow();
  563.     
  564.     // Keep searching until a visible window whose windowKind is not
  565.     // kApplicationFloaterKind is found, or the end of the window list is reached.
  566.     
  567.     while ((theWindow != nil) && (GetWindowKind(theWindow) == kApplicationFloaterKind)) {
  568.         do {
  569.             theWindow = GetNextWindow(theWindow);
  570.         } while ((theWindow != nil) && (GetWindowVisible(theWindow) == false));
  571.     }
  572.  
  573.     return theWindow;
  574. }
  575.  
  576. //
  577. // LastFloatingWindow
  578. //
  579. //    Return the last floating window, whether it is visible or not, or nil if there are
  580. //    no floating windows.
  581. //
  582.  
  583. pascal WindowRef LastFloatingWindow(void)
  584. {
  585.     WindowRef    theWindow;
  586.     WindowRef    lastFloatingWindow;
  587.     
  588.     theWindow = GetWindowList();
  589.     lastFloatingWindow = nil;
  590.     
  591.     // We have to search the entire window list because we don’t know what the windowKind
  592.     // of other windows in the list might be, and we have account for the fact that a modal
  593.     // dialog is up.
  594.     
  595.     while (theWindow != nil) {
  596.         if (GetWindowKind(theWindow) == kApplicationFloaterKind)
  597.             lastFloatingWindow = theWindow;
  598.         theWindow = GetNextWindow(theWindow);
  599.     }
  600.     
  601.     return lastFloatingWindow;
  602. }
  603.  
  604. //
  605. // WindowIsModal
  606. //
  607. //    Determines if a window is modal based upon the value of its windowKind and window variant.
  608. //
  609.  
  610. pascal Boolean WindowIsModal(WindowRef windowReference)
  611. {
  612.     short    windowVariant;
  613.     
  614.     windowVariant = GetWVariant((WindowPtr) windowReference);
  615.     if ((GetWindowKind(windowReference) == dialogKind) &&
  616.         ((windowVariant == dBoxProc) ||
  617.         (windowVariant == movableDBoxProc)))
  618.         return true;
  619.     else
  620.         return false;
  621. }
  622.  
  623. //
  624. // DeactivateFloatersAndFirstDocumentWindow
  625. //
  626. //    Send deactivate events to all visible floating windows and the active document
  627. //    window.  This routine is called before a modal dialog is presented.
  628. //
  629.  
  630. pascal void DeactivateFloatersAndFirstDocumentWindow(void)
  631. {
  632.     WindowRef            firstWindow;
  633.     WindowRef            secondDocumentWindow;
  634.     WindowRef            currentWindow;
  635.     
  636.     // First, make sure the window ordering hasn’t been changed behind our back
  637.     ValidateWindowList();
  638.     
  639.     // Start from the frontmost window on the screen, and keep going until
  640.     // we’ve reached the second document window.
  641.     
  642.     firstWindow = (WindowRef) FrontWindow();
  643.     secondDocumentWindow = FrontNonFloatingWindow();
  644.     if (secondDocumentWindow != nil)
  645.         secondDocumentWindow = GetNextWindow(secondDocumentWindow);
  646.         
  647.     currentWindow = firstWindow;
  648.     while (currentWindow != secondDocumentWindow) {
  649.         if (GetWindowVisible(currentWindow))
  650.             DeactivateWindow(currentWindow);
  651.         currentWindow = GetNextWindow(currentWindow);
  652.     }
  653. }
  654.  
  655. //
  656. // ActivateFloatersAndFirstDocumentWindow
  657. //
  658. //    ActivateFloatersAndFirstDocumentWindow should be called after a modal dialog
  659. //    is dismissed.  If the application is in the background when this routine is
  660. //    called (like when a moveable modal progress dialog was up and then disappears)
  661. //    this routine calls SuspendFloatingWindows to hide any visible floating windows
  662. //    instead.
  663. //
  664.  
  665. pascal void ActivateFloatersAndFirstDocumentWindow(void)
  666. {
  667.     ProcessSerialNumber    currentPSN;
  668.     ProcessSerialNumber    frontPSN;
  669.     WindowRef            firstWindow;
  670.     WindowRef            secondDocumentWindow;
  671.     WindowRef            currentWindow;
  672.     OSErr                getFrontProcessResult;
  673.     OSErr                getCurrentProcessResult;
  674.     OSErr                sameProcessResult;
  675.     Boolean                isSameProcess;
  676.     
  677.     // See if the this process is in the background.  If it is, then the floating
  678.     // windows should be hidden instead of reactivated, so SuspendFloatingWindows()
  679.     // is called instead.
  680.     
  681.     getFrontProcessResult = GetFrontProcess(&frontPSN);
  682.     getCurrentProcessResult = GetCurrentProcess(¤tPSN);
  683.     
  684.     if ((getFrontProcessResult == noErr) && (getCurrentProcessResult == noErr))
  685.         sameProcessResult = SameProcess(&frontPSN, ¤tPSN, &isSameProcess);
  686.         
  687.     if ((sameProcessResult == noErr) && (isSameProcess == false))
  688.         SuspendFloatingWindows();
  689.     else {
  690.         firstWindow = (WindowRef) FrontWindow();
  691.         secondDocumentWindow = FrontNonFloatingWindow();
  692.         if (secondDocumentWindow != nil)
  693.             secondDocumentWindow = GetNextWindow(secondDocumentWindow);
  694.         
  695.         currentWindow = firstWindow;
  696.         while (currentWindow != secondDocumentWindow) {
  697.             if (GetWindowVisible(currentWindow))
  698.                 ActivateWindow(currentWindow);
  699.             currentWindow = GetNextWindow(currentWindow);
  700.         }
  701.     }
  702. }
  703.  
  704. //
  705. // SuspendFloatingWindows
  706. //
  707. //    Hide any visible floating windows, and deactivate the frontmost document window.
  708. //    This routine should be called when an application recieves a suspend event.
  709. //
  710.  
  711. pascal void SuspendFloatingWindows(void)
  712. {
  713.     WindowRef    currentWindow;
  714.     Boolean        windowIsVisible;
  715.     
  716.     currentWindow = (WindowRef) GetWindowList();
  717.     if (GetWindowKind(currentWindow) != kApplicationFloaterKind)
  718.         return;
  719.         
  720.     do {
  721.         windowIsVisible = GetWindowVisible(currentWindow);
  722.         SetWasVisible(currentWindow, windowIsVisible);
  723.         if (windowIsVisible)
  724.             ShowHide((WindowPtr) currentWindow, false);
  725.         currentWindow = GetNextWindow(currentWindow);
  726.     } while ((currentWindow != nil) &&
  727.              (GetWindowKind(currentWindow) == kApplicationFloaterKind));
  728.     
  729.     // The floating windows are now hidden.  Deactivate the first visible
  730.     // document window.
  731.     
  732.     currentWindow = FrontNonFloatingWindow();
  733.     if (currentWindow != nil)
  734.         DeactivateWindow(currentWindow);
  735. }
  736.  
  737. //
  738. // ResumeFloatingWindows
  739. //
  740. //    Reveal floating windows that were hidden by SuspendFloatingWindows.  An
  741. //    activate event is sent to each one as it is revealed.  The frontmost document
  742. //    is also sent an activate event.
  743. //
  744.  
  745. pascal void ResumeFloatingWindows(void)
  746. {
  747.     WindowRef    currentWindow;
  748.     Boolean        windowWasVisible;
  749.     
  750.     currentWindow = GetWindowList();
  751.     if (GetWindowKind(currentWindow) != kApplicationFloaterKind)
  752.         return;
  753.         
  754.     do {
  755.         windowWasVisible = GetWasVisible(currentWindow);
  756.         if (windowWasVisible) {
  757.             ShowHide((WindowPtr) currentWindow, true);
  758.             ActivateWindow(currentWindow);
  759.         }
  760.         currentWindow = GetNextWindow(currentWindow);
  761.     } while ((currentWindow != nil) &&
  762.              (GetWindowKind(currentWindow) == kApplicationFloaterKind));
  763.  
  764.     // The floating windows have been revealed.  Activate the first document
  765.     // window as well.
  766.     
  767.     currentWindow = FrontNonFloatingWindow();
  768.     if (currentWindow != nil)
  769.         ActivateWindow(currentWindow);
  770. }
  771.  
  772. //
  773. // ActivateWindow
  774. //
  775. //    Activates the window by highlighting it, and calling its activate handler.
  776. //
  777.  
  778. void ActivateWindow(WindowRef theWindow)
  779. {
  780.     HighlightAndActivateWindow(theWindow, kActivateWindow);
  781. }
  782.  
  783. //
  784. // DeactivateWindow
  785. //
  786. //    Deactivates the window by unhighlighting it and calling its activate handler.
  787. //
  788.  
  789. void DeactivateWindow(WindowRef theWindow)
  790. {
  791.     HighlightAndActivateWindow(theWindow, kDeactivateWindow);
  792. }
  793.  
  794. //
  795. // HighlightAndActivateWindow
  796. //
  797. //    Common code for ActivateWindow and DeactivateWindow.  Does actual highlighting
  798. //    and calling of the activate handler.
  799. //
  800.  
  801. void HighlightAndActivateWindow(WindowRef theWindow, Boolean activate)
  802. {
  803.     ActivateHandlerUPP    activateHandlerProc;
  804.     
  805.     activateHandlerProc = GetActivateHandlerProc(theWindow);
  806.     HiliteWindow((WindowPtr) theWindow, activate);
  807.     if (activateHandlerProc != nil)
  808.         CallActivateHandlerProc(activateHandlerProc, theWindow, activate);
  809. }
  810.  
  811. //
  812. // ValidateWindowList
  813. //
  814. //    Code external to the application might call SelectWindow or FrontWindow because they
  815. //    don’t know any better. If the application has floating windows that are invisible
  816. //    when some other code calls FrontWindow then SelectWindow, a document window will get
  817. //    pulled in front of the invisible floating windows. This routine makes sure everything
  818. //    is right with the world, or at least the window list. It assumes that the floating
  819. //    windows are invisible, so visually, nothing changes on the screen. This means that
  820. //    the code doesn’t call CalcVBehind or PaintBehind. If I wanted to be more general,
  821. //    those two calls would have to be made. Ideally, this routine only needs to be called
  822. //    the first time window ordering changes after a foreign window was opened in your
  823. //    applicaiton. I’m actually calling it every time ShowReferencedWindow is called on
  824. //    a floating window, and when new document windows are created or closed, just to be
  825. //    safe.
  826. //
  827.  
  828. pascal void ValidateWindowList(void)
  829. {
  830.     WindowRef    currentWindow = GetWindowList();
  831.     WindowRef    lastFloatingWindow = LastFloatingWindow();
  832.     WindowRef    firstFloatingWindow = nil;
  833.     WindowRef    documentWindowsToMove = nil;
  834.     WindowRef    lastDocumentWindowAdded = nil;
  835.     WindowRef    previousWindow = nil;
  836.     
  837.     if (currentWindow) {
  838.     
  839.     // First, gather up all the document windows in front of floating windows. We iterate
  840.     // through the window list until a floating window is encountered.
  841.     
  842.         do {
  843.             if (GetWindowKind(currentWindow) == kApplicationFloaterKind) {
  844.                 firstFloatingWindow = currentWindow;
  845.                 break;
  846.             }
  847.             else {
  848.                 SetNextWindow(previousWindow, GetNextWindow(currentWindow));
  849.  
  850.                 if (documentWindowsToMove == nil)
  851.                     documentWindowsToMove = currentWindow;
  852.                 else
  853.                     SetNextWindow(lastDocumentWindowAdded, currentWindow);
  854.                 lastDocumentWindowAdded = currentWindow;
  855.                 
  856.                 previousWindow = currentWindow;
  857.                 currentWindow = GetNextWindow(currentWindow);
  858.             }
  859.         } while (currentWindow);
  860.         
  861.     // Now put them back in their place.
  862.     
  863.         if (documentWindowsToMove && firstFloatingWindow) {
  864.             SetNextWindow(lastDocumentWindowAdded, GetNextWindow(lastFloatingWindow));
  865.             SetNextWindow(lastFloatingWindow, documentWindowsToMove);
  866.             
  867.     // If the first window in the window list was a document window, and there are
  868.     // floating windows, then make the floating window the first window in the window
  869.     // list.
  870.             if (documentWindowsToMove == GetWindowList())
  871.                 SetWindowList(firstFloatingWindow);
  872.         }
  873.     }
  874. }
  875.  
  876. //
  877. // Getters and Setters
  878. //
  879.  
  880. //    GetWindowPortRect — returns the portRect from the window’s GrafPort.
  881.  
  882. pascal void GetWindowPortRect(WindowRef windowReference, Rect *portRect)
  883. {
  884.     *portRect = ((WindowPtr) windowReference)->portRect;
  885. }
  886.  
  887.  
  888. // Get/SetWindowKind — get and set the windowKind field of the window
  889.  
  890. pascal short GetWindowKind(WindowRef windowReference)
  891. {
  892.     return ((WindowPeek) windowReference)->windowKind;
  893. }
  894.  
  895. pascal void SetWindowKind(WindowRef windowReference, short windowKind)
  896. {
  897.     ((WindowPeek) windowReference)->windowKind = windowKind;
  898. }
  899.  
  900.  
  901. // Get/SetWindowVisible — get and set the visible field for a window
  902.  
  903. pascal Boolean GetWindowVisible(WindowRef windowReference)
  904. {
  905.     return (windowReference->theWindow.visible);
  906. }
  907.  
  908. pascal void SetWindowVisible(WindowRef windowReference, Boolean windowVisible)
  909. {
  910.     windowReference->theWindow.visible = windowVisible;
  911. }
  912.  
  913.  
  914. // Get/SetWindowHilite — get and set the hilited field of a window
  915.  
  916. pascal Boolean GetWindowHilite(WindowRef windowReference)
  917. {
  918.     return (windowReference->theWindow.hilited);
  919. }
  920.  
  921. pascal void SetWindowHilite(WindowRef windowReference, Boolean windowHilite)
  922. {
  923.     windowReference->theWindow.hilited = windowHilite;
  924. }
  925.  
  926.  
  927. // Get/SetNextWindow — get and set the window after this window
  928.  
  929. pascal WindowRef GetNextWindow(WindowRef windowReference)
  930. {
  931.     return ((WindowRef) (windowReference->theWindow.nextWindow));
  932. }
  933.  
  934. pascal void SetNextWindow(WindowRef windowReference, WindowRef nextWindow)
  935. {
  936.     windowReference->theWindow.nextWindow = (WindowPeek) nextWindow;
  937. }
  938.  
  939.  
  940. // GetContentRegion — return the window’s content region
  941.  
  942. pascal RgnHandle GetContentRegion(WindowRef windowReference)
  943. {
  944.     return (windowReference->theWindow.contRgn);
  945. }
  946.  
  947.  
  948. // GetStructureRegion — return the window’s structure region
  949.  
  950. pascal RgnHandle GetStructureRegion(WindowRef windowReference)
  951. {
  952.     return (windowReference->theWindow.strucRgn);
  953. }
  954.  
  955.  
  956. // GetWindowDefPRoc - return a handle to the window’s definition procedure
  957.  
  958. pascal Handle GetWindowDefProc(WindowRef windowReference)
  959. {
  960.     return (windowReference->theWindow.windowDefProc);
  961. }
  962.  
  963.  
  964. // Get/SetActivateHandlerProc — get and set the activate event handler for this window
  965.  
  966. pascal ActivateHandlerUPP GetActivateHandlerProc(WindowRef windowReference)
  967. {
  968.     return (windowReference->activateHandlerProc);
  969. }
  970.  
  971. pascal void SetActivateHandlerProc(WindowRef windowReference, ActivateHandlerUPP activateHandlerProc)
  972. {
  973.     windowReference->activateHandlerProc = activateHandlerProc;
  974. }
  975.  
  976.  
  977. // Get/SetWasVisible — save and restore the visible field of a window
  978.  
  979. pascal Boolean GetWasVisible(WindowRef windowReference)
  980. {
  981.     return (windowReference->wasVisible);
  982. }
  983.  
  984. pascal void SetWasVisible(WindowRef windowReference, Boolean wasVisible)
  985. {
  986.     windowReference->wasVisible = wasVisible;
  987. }
  988.  
  989.  
  990. // GetWindowList — Return the first window in the application’s window list from low memory.
  991.  
  992. WindowRef GetWindowList(void)
  993. {
  994.     return (* (WindowRef *) WindowList);
  995. }
  996.  
  997. // SetWindowList — Set the first window in this process’ window list.
  998.  
  999. void SetWindowList(WindowRef windowReference)
  1000. {
  1001.     (* (WindowRef *) WindowList) = windowReference;
  1002. }